
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using MudEngine;
using MudEngine.Parsing.AST;
using MudEngine.Runtime;

namespace MudEngine.Parsing {



public class Parser {
	public const int _EOF = 0;
	public const int _ident = 1;
	public const int _floatcon = 2;
	public const int _intcon = 3;
	public const int _stringcon = 4;
	public const int _charcon = 5;
	public const int _array = 6;
	public const int _bool = 7;
	public const int _case = 8;
	public const int _catch = 9;
	public const int _char = 10;
	public const int _default = 11;
	public const int _double = 12;
	public const int _enum = 13;
	public const int _float = 14;
	public const int _int = 15;
	public const int _long = 16;
	public const int _var = 17;
	public const int _map = 18;
	public const int _object = 19;
	public const int _short = 20;
	public const int _string = 21;
	public const int _struct = 22;
	public const int _void = 23;
	public const int _comma = 24;
	public const int _semicolon = 25;
	public const int _lpar = 26;
	public const int _rpar = 27;
	public const int _lbrack = 28;
	public const int _rbrack = 29;
	public const int _lbrace = 30;
	public const int _rbrace = 31;
	public const int _assgn = 32;
	public const int _ellipsis = 33;
	public const int _range = 34;
	public const int _arrow = 35;
	public const int _dcolon = 36;
	public const int _colon = 37;
	public const int _qmark = 38;
	public const int _inherit = 39;
	public const int _public = 40;
	public const int _private = 41;
	public const int _readonly = 42;
	public const int _static = 43;
	public const int _qor = 44;
	public const int _qand = 45;
	public const int _bor = 46;
	public const int _band = 47;
	public const int _bxor = 48;
	public const int _eq = 49;
	public const int _neq = 50;
	public const int _lt = 51;
	public const int _gt = 52;
	public const int _lte = 53;
	public const int _gte = 54;
	public const int _lsh = 55;
	public const int _rsh = 56;
	public const int _add = 57;
	public const int _sub = 58;
	public const int _mul = 59;
	public const int _div = 60;
	public const int _mod = 61;
	public const int _lams = 62;
	public const int _lame = 63;
	public const int _maps = 64;
	public const int _arrays = 65;
	public const int _continue = 66;
	public const int _break = 67;
	public const int _return = 68;
	public const int _if = 69;
	public const int _else = 70;
	public const int _switch = 71;
	public const int _while = 72;
	public const int _do = 73;
	public const int _for = 74;
	public const int _foreach = 75;
	public const int _in = 76;
	public const int _assignmul = 77;
	public const int _assigndiv = 78;
	public const int _assignmod = 79;
	public const int _assignadd = 80;
	public const int _assignsub = 81;
	public const int _assignshl = 82;
	public const int _assignshr = 83;
	public const int _assignand = 84;
	public const int _assignxor = 85;
	public const int _assignor = 86;
	public const int _bnot = 87;
	public const int _not = 88;
	public const int _true = 89;
	public const int _false = 90;
	public const int _null = 91;
	public const int _incr = 92;
	public const int _decr = 93;
	public const int maxT = 94;
	public const int _ppBreak = 95;
	public const int _ppDefine = 96;
	public const int _ppUndef = 97;
	public const int _ppIf = 98;
	public const int _ppElif = 99;
	public const int _ppElse = 100;
	public const int _ppEndif = 101;
	public const int _ppInclude = 102;

	const bool T = true;
	const bool x = false;
	const int minErrDist = 2;
	
	public Scanner scanner;
	public Errors  errors;
	public ObjectManager ObjectManager { get; set; }
	private CompilationUnit CompilationUnit;

	public Token t;    // last recognized token
	public Token la;   // lookahead token
	int errDist = minErrDist;

static BitArray
	startOfTypeName = NewBitArray(_void, _char, _short, _int, _long, _double, _float, _enum, _string, _object, _bool, _var, _map, _array);

private static BitArray NewBitArray(params int[] val) {
	BitArray s = new BitArray(128);
	foreach (int x in val) s[x] = true;
	return s;
}

//---------- LL(1) conflict resolvers ------------------------------

private StringCollection Symbols = new StringCollection();

private bool IsTypeName(Token x) {
	if (x.kind != _ident)
		return false;
    return !Symbols.Contains(x.val);
}

bool IsType0() { // return true if the next token is a type name
	return IsTypeName(la);
} 

bool IsType1() { // return true if "(" TypeName
	if (la.kind != _lpar)
		return false;
	Token x = scanner.Peek();
	if (x.kind == _colon || x.kind == _lbrack)
		return false;
	if (startOfTypeName[x.kind])
		return true;
	return IsTypeName(x);
}

bool Continued() { // return true if not "," "}"
	if (la.kind == _comma) {
		Token x = scanner.Peek();
		if (x.kind == _rbrace) return false;
	}
	return true; 
}

bool Continued1() { // return true if ",", which is not followed by "..."
	if (la.kind == _comma) {
		Token x = scanner.Peek();
		if (x.kind != _ellipsis) return true;
	}
	return false; 
}

bool NotFinalComma () {
	int peek = Peek(1).kind;
	return la.kind == _comma && peek != _rbrace && peek != _rbrack;
}

bool IsFieldDecl () {
	int peek = Peek(1).kind;
	return la.kind == _ident && (peek == _comma || peek == _assgn || peek == _semicolon);
}

Token Peek (int n) {
	scanner.ResetPeek();
	Token x = la;
	while (n > 0)
	{
		x = scanner.Peek();
		n--;
	}
	return x;
}

// "[" ("," | "]")
bool IsDims () {
	int peek = Peek(1).kind;
	return la.kind == _lbrack && (peek == _comma || peek == _rbrack);
}

// skip: { "[" { "," } "]" | "*" }
// !!! Proceeds from current peek position !!!
bool IsDims (ref Token pt) {
	for (;;) {
		if (pt.kind == _lbrack) {
			do pt = scanner.Peek();
			while (pt.kind == _comma);
			if (pt.kind != _rbrack)
                return false;
		} else
            break;
		pt = scanner.Peek();
	}
	return true;
}

// Type ident
bool IsLocalVarDecl () {
	Token pt = la;
	scanner.ResetPeek();
	
	if (startOfTypeName[la.kind] || la.kind == _void) {
        pt = scanner.Peek();
        if (la.kind == _void)
            return false;
	} else if (la.kind == _ident && Peek(1).kind != _ident) {
		return false;
	}
	
	return IsDims(ref pt) && pt.kind == _ident;
}

private FunctionDeclaration _func;



	public Parser(Scanner scanner) {
		this.scanner = scanner;
		errors = new Errors();
	}

	void SynErr (int n) {
		if (errDist >= minErrDist) errors.SynErr(la.line, la.col, n);
		errDist = 0;
	}

	public void SemErr (string msg) {
		if (errDist >= minErrDist) errors.SemErr(t.line, t.col, msg);
		errDist = 0;
	}
	
	void Get () {
		for (;;) {
			t = la;
			la = scanner.Scan();
			if (la.kind <= maxT) { ++errDist; break; }
				if (la.kind == 95) {
				}
				if (la.kind == 96) {
				}
				if (la.kind == 97) {
				}
				if (la.kind == 98) {
				}
				if (la.kind == 99) {
				}
				if (la.kind == 100) {
				}
				if (la.kind == 101) {
				}
				if (la.kind == 102) {
				}

			la = t;
		}
	}
	
	void Expect (int n) {
		if (la.kind==n) Get(); else { SynErr(n); }
	}
	
	bool StartOf (int s) {
		return set[s, la.kind];
	}
	
	void ExpectWeak (int n, int follow) {
		if (la.kind == n) Get();
		else {
			SynErr(n);
			while (!StartOf(follow)) Get();
		}
	}


	bool WeakSeparator(int n, int syFol, int repFol) {
		int kind = la.kind;
		if (kind == n) {Get(); return true;}
		else if (StartOf(repFol)) {return false;}
		else {
			SynErr(n);
			while (!(set[syFol, kind] || set[repFol, kind] || set[0, kind])) {
				Get();
				kind = la.kind;
			}
			return StartOf(syFol);
		}
	}

	
	void C() {
		this.CompilationUnit = new CompilationUnit(); InheritDeclaration id = null; 
		while (la.kind == 39) {
			InheritDirective(out id);
			this.CompilationUnit.AddNode(id); 
			object_t o = this.ObjectManager.FindObject(id.Inherit);
			if (o == null)
			{
			la.kind = 0; // put in EOF to spoof compiler
			return;
			}
			else
			{
			id.Program = o.Program;
			}
			
		}
		ExternalDecl();
		while (StartOf(1)) {
			ExternalDecl();
		}
	}

	void InheritDirective(out InheritDeclaration id) {
		Expect(39);
		Expect(4);
		id = new InheritDeclaration(t.val); id.Column = t.col; id.Line = t.line; 
		Expect(25);
	}

	void ExternalDecl() {
		Modifiers m = new Modifiers(this); 
		while (StartOf(2)) {
			MemberModifier(m);
		}
		MemberDeclarator(m);
	}

	void MemberModifier(Modifiers m) {
		if (la.kind == 41) {
			Get();
			m.Add(Modifier.@private); 
		} else if (la.kind == 40) {
			Get();
			m.Add(Modifier.@public); 
		} else if (la.kind == 42) {
			Get();
			m.Add(Modifier.@readonly); 
		} else if (la.kind == 43) {
			Get();
			m.Add(Modifier.@static); 
		} else SynErr(95);
	}

	void MemberDeclarator(Modifiers m) {
		AType type = AType.TYPE_INT; BlockStatement block = null; 
		if (la.kind == 13) {
			Get();
			Expect(1);
			if (la.kind == 37) {
				Get();
				TypeSpecifier(out type);
			}
			EnumDeclaration ed = new EnumDeclaration(this, m, type, t.val); 
			EnumBody(ed);
			this.CompilationUnit.AddNode(ed); 
			if (la.kind == 25) {
				Get();
			}
		} else if (StartOf(3)) {
			TypeSpecifier(out type);
			if (IsFieldDecl()) {
				FieldDeclaration fd = null; 
				Field(out fd);
				fd.Modifiers = m; fd.Type = type; this.CompilationUnit.AddNode(fd); Symbols.Add(fd.Name); 
				while (la.kind == 24) {
					Get();
					Field(out fd);
					fd.Modifiers = m; fd.Type = type; this.CompilationUnit.AddNode(fd); Symbols.Add(fd.Name); 
				}
				Expect(25);
			} else if (la.kind == 1) {
				Get();
				FunctionDeclaration functionDeclaration = new FunctionDeclaration(m, type, t.val); _func = functionDeclaration; Symbols.Add(functionDeclaration.Name); 
				Expect(26);
				if (StartOf(3)) {
					FormalParams(functionDeclaration);
					if (la.kind == 24) {
						Get();
						Expect(33);
						functionDeclaration.AddParameterDeclaration(new DynamicParameterDeclaration()); 
					}
				}
				Expect(27);
				Block(out block);
				functionDeclaration.Body = block; this.CompilationUnit.AddNode(functionDeclaration); 
			} else SynErr(96);
		} else SynErr(97);
	}

	void TypeSpecifier(out AType type) {
		type = AType.TYPE_VOID; 
		switch (la.kind) {
		case 23: {
			Get();
			break;
		}
		case 10: {
			Get();
			type = AType.TYPE_STRING; 
			break;
		}
		case 21: {
			Get();
			type = AType.TYPE_STRING; 
			break;
		}
		case 19: {
			Get();
			type = AType.TYPE_OBJECT; 
			break;
		}
		case 20: {
			Get();
			type = AType.TYPE_SHORT; 
			break;
		}
		case 15: {
			Get();
			type = AType.TYPE_INT; 
			break;
		}
		case 16: {
			Get();
			type = AType.TYPE_LONG; 
			break;
		}
		case 12: {
			Get();
			type = AType.TYPE_REAL; 
			break;
		}
		case 7: {
			Get();
			type = AType.TYPE_BOOL; 
			break;
		}
		case 18: {
			Get();
			type = AType.TYPE_MAP; 
			break;
		}
		case 17: {
			Get();
			type = AType.TYPE_VAR; 
			break;
		}
		case 6: {
			Get();
			type = AType.TYPE_ARRAY; 
			break;
		}
		case 1: {
			Get();
			type = new AType(t.val); 
			break;
		}
		default: SynErr(98); break;
		}
	}

	void EnumBody(EnumDeclaration ed) {
		Expect(30);
		if (la.kind == 1) {
			Get();
			ed.AddNode(new EnumMemberDeclaration(t.val)); 
			while (NotFinalComma()) {
				Expect(24);
				Expect(1);
				ed.AddNode(new EnumMemberDeclaration(t.val)); 
			}
			if (la.kind == 24) {
				Get();
			}
		}
		Expect(31);
	}

	void Field(out FieldDeclaration fd) {
		fd = null; Expression e = null; 
		Expect(1);
		fd = new FieldDeclaration(t.val); 
		if (la.kind == 32) {
			Get();
			Expr(out e);
			fd.Initializer = e; 
		}
	}

	void FormalParams(FunctionDeclaration fd) {
		ParameterDeclaration pd = null; 
		Par(out pd);
		fd.AddParameterDeclaration(pd); Symbols.Add(pd.Name); 
		if (Continued1()) {
			Expect(24);
			FormalParams(fd);
		}
	}

	void Block(out BlockStatement block) {
		block = new BlockStatement(); Statement s1 = null; AstNodeCollection nodes = block.Children; 
		Expect(30);
		while (StartOf(4)) {
			if (IsLocalVarDecl()) {
				LocalVarDecl(nodes);
				Expect(25);
			} else {
				Stat(out s1);
				block.AddNode(s1); 
			}
		}
		Expect(31);
	}

	void Par(out ParameterDeclaration pd) {
		AType type; 
		TypeSpecifier(out type);
		Expect(1);
		pd = new ParameterDeclaration(t.val, type); 
	}

	void Expr(out Expression s) {
		Expression e, e1; 
		AssignExpr(out e);
		s = e; 
		while (la.kind == 24) {
			Get();
			AssignExpr(out e1);
			Console.WriteLine("Missed AssignExpr token."); 
		}
	}

	void AssignExpr(out Expression s) {
		Expression e, e1; AssignmentOperatorType op; 
		CondExpr(out e);
		s = e; 
		if (StartOf(5)) {
			AssignOp(out op);
			AssignExpr(out e1);
			s = new AssignmentExpression(e, op, e1); 
		}
	}

	void CondExpr(out Expression s) {
		Expression e, e1, e2; 
		LogOrExpr(out e);
		s = e; 
		if (la.kind == 38) {
			Get();
			Expr(out e1);
			Expect(37);
			CondExpr(out e2);
			s = new IfElseExpression(e, new ExpressionStatement(e1), new ExpressionStatement(e2)); 
		}
	}

	void AssignOp(out AssignmentOperatorType op) {
		op = AssignmentOperatorType.Any; 
		switch (la.kind) {
		case 32: {
			Get();
			op = AssignmentOperatorType.Assign; 
			break;
		}
		case 77: {
			Get();
			op = AssignmentOperatorType.Multiply; 
			break;
		}
		case 78: {
			Get();
			op = AssignmentOperatorType.Divide; 
			break;
		}
		case 79: {
			Get();
			op = AssignmentOperatorType.Modulus; 
			break;
		}
		case 80: {
			Get();
			op = AssignmentOperatorType.Add; 
			break;
		}
		case 81: {
			Get();
			op = AssignmentOperatorType.Subtract; 
			break;
		}
		case 82: {
			Get();
			op = AssignmentOperatorType.ShiftLeft; 
			break;
		}
		case 83: {
			Get();
			op = AssignmentOperatorType.ShiftRight; 
			break;
		}
		case 84: {
			Get();
			op = AssignmentOperatorType.BitwiseAnd; 
			break;
		}
		case 85: {
			Get();
			op = AssignmentOperatorType.ExclusiveOr; 
			break;
		}
		case 86: {
			Get();
			op = AssignmentOperatorType.BitwiseOr; 
			break;
		}
		default: SynErr(99); break;
		}
	}

	void LogOrExpr(out Expression s) {
		Expression e, e1; 
		LogAndExpr(out e);
		s = e; 
		while (la.kind == 44) {
			Get();
			LogAndExpr(out e1);
			s = new BinaryExpression(e, BinaryOperatorType.ConditionalOr, e1); 
		}
	}

	void LogAndExpr(out Expression s) {
		Expression e, e1; 
		OrExpr(out e);
		s = e; 
		while (la.kind == 45) {
			Get();
			OrExpr(out e1);
			s = new BinaryExpression(e, BinaryOperatorType.ConditionalAnd, e1); 
		}
	}

	void OrExpr(out Expression s) {
		Expression e, e1; 
		XorExpr(out e);
		s = e; 
		while (la.kind == 46) {
			Get();
			XorExpr(out e1);
			s = new BinaryExpression(e, BinaryOperatorType.BitwiseOr, e1); 
		}
	}

	void XorExpr(out Expression s) {
		Expression e, e1; 
		AndExpr(out e);
		s = e; 
		while (la.kind == 48) {
			Get();
			AndExpr(out e1);
			s = new BinaryExpression(e, BinaryOperatorType.ExclusiveOr, e1); 
		}
	}

	void AndExpr(out Expression s) {
		Expression e, e1; 
		EqlExpr(out e);
		s = e; 
		while (la.kind == 47) {
			Get();
			EqlExpr(out e1);
			s = new BinaryExpression(e, BinaryOperatorType.BitwiseAnd, e1); 
		}
	}

	void EqlExpr(out Expression s) {
		Expression e, e1; BinaryOperatorType op = BinaryOperatorType.Equality; 
		RelExpr(out e);
		s = e; 
		while (la.kind == 49 || la.kind == 50) {
			if (la.kind == 49) {
				Get();
			} else {
				Get();
				op = BinaryOperatorType.InEquality; 
			}
			RelExpr(out e1);
			s = new BinaryExpression(e, op, e1); 
		}
	}

	void RelExpr(out Expression s) {
		Expression e, e1; BinaryOperatorType op = BinaryOperatorType.LessThan; 
		ShiftExpr(out e);
		s = e; 
		while (StartOf(6)) {
			if (la.kind == 51) {
				Get();
			} else if (la.kind == 52) {
				Get();
				op = BinaryOperatorType.GreaterThan; 
			} else if (la.kind == 53) {
				Get();
				op = BinaryOperatorType.LessThanOrEqual; 
			} else {
				Get();
				op = BinaryOperatorType.GreaterThanOrEqual; 
			}
			ShiftExpr(out e1);
			s = new BinaryExpression(e, op, e1); 
		}
	}

	void ShiftExpr(out Expression s) {
		Expression e, e1; BinaryOperatorType op = BinaryOperatorType.ShiftLeft; 
		AddExpr(out e);
		s = e; 
		while (la.kind == 55 || la.kind == 56) {
			if (la.kind == 55) {
				Get();
			} else {
				Get();
				op = BinaryOperatorType.ShiftRight; 
			}
			AddExpr(out e1);
			s = new BinaryExpression(e, op, e1); 
		}
	}

	void AddExpr(out Expression s) {
		Expression e, e1 = null, e2 = null; BinaryOperatorType op = BinaryOperatorType.Any; 
		MultExpr(out e);
		s = e; 
		while (la.kind == 57 || la.kind == 58) {
			if (la.kind == 57) {
				Get();
				op = BinaryOperatorType.Add; 
			} else {
				Get();
				op = BinaryOperatorType.Subtract; 
			}
			MultExpr(out e1);
			if (e2 != null) e1 = new BinaryExpression(e2, op, e1); e2 = e1; 
		}
		if (e1 != null) s = new BinaryExpression(e, op, e1); 
	}

	void MultExpr(out Expression s) {
		Expression e, e1; BinaryOperatorType op = BinaryOperatorType.Any; 
		CastExpr(out e);
		s = e; 
		while (la.kind == 59 || la.kind == 60 || la.kind == 61) {
			if (la.kind == 59) {
				Get();
				op = BinaryOperatorType.Multiply; 
			} else if (la.kind == 60) {
				Get();
				op = BinaryOperatorType.Divide; 
			} else {
				Get();
				op = BinaryOperatorType.Modulus; 
			}
			CastExpr(out e1);
			s = new BinaryExpression(e, op, e1); 
		}
	}

	void CastExpr(out Expression s) {
		Expression e; s = null; AType type; ArrayInitializerExpression aie = null; 
		if (IsType1()) {
			Expect(26);
			TypeSpecifier(out type);
			Expect(27);
			CastExpr(out e);
			s = new CastExpression(type, e); 
		} else if (StartOf(7)) {
			UnaryExpr(out e);
			s = e; 
		} else if (la.kind == 64) {
			MapInitExpr(out e);
			s = e; 
		} else if (la.kind == 65) {
			ArrayInitExpr(out aie);
			s = aie; 
		} else if (la.kind == 62) {
			LambdaExpr(out e);
			s = e; 
		} else SynErr(100);
	}

	void UnaryExpr(out Expression s) {
		s = null; Expression e; UnaryOperatorType op = UnaryOperatorType.Any; 
		while (la.kind == 92 || la.kind == 93) {
			if (la.kind == 92) {
				Get();
				op = UnaryOperatorType.Increment; 
			} else {
				Get();
				op = UnaryOperatorType.Decrement; 
			}
		}
		if (StartOf(8)) {
			PostfixExpr(out e);
			s = (op == UnaryOperatorType.Any?e:new UnaryExpression(op, e)); 
		} else if (StartOf(9)) {
			UnaryOp(out op);
			CastExpr(out e);
			s = (op == UnaryOperatorType.Any?e:new UnaryExpression(op, e)); 
		} else if (la.kind == 9) {
			Get();
			Expect(26);
			Expr(out e);
			Expect(27);
			s = new CatchExpression(e); 
		} else SynErr(101);
	}

	void MapInitExpr(out Expression s) {
		MapInitializerExpression mie = new MapInitializerExpression(); 
		Expect(64);
		if (StartOf(10)) {
			AssocPair(mie);
			while (NotFinalComma()) {
				Expect(24);
				AssocPair(mie);
			}
			if (la.kind == 24) {
				Get();
			}
		}
		Expect(29);
		Expect(27);
		s = mie; 
	}

	void ArrayInitExpr(out ArrayInitializerExpression aie) {
		aie = new ArrayInitializerExpression(); Expression e = null; 
		Expect(65);
		if (StartOf(10)) {
			CondExpr(out e);
			aie.AddNode(e); 
			while (NotFinalComma()) {
				Expect(24);
				CondExpr(out e);
				aie.AddNode(e); 
			}
			if (la.kind == 24) {
				Get();
			}
		}
		Expect(31);
		Expect(27);
	}

	void LambdaExpr(out Expression s) {
		Expression e; 
		Expect(62);
		Expr(out e);
		Expect(63);
		s = new LambdaExpression(e); 
	}

	void AssocPair(MapInitializerExpression mie) {
		Expression e = null, e1 = null; 
		CondExpr(out e);
		Expect(37);
		CondExpr(out e1);
		mie.AddAssocPair(e, e1); 
	}

	void PostfixExpr(out Expression s) {
		Expression e, e1 = null, e2 = null, e_x = null; UnaryOperatorType op = UnaryOperatorType.Any; InvocationExpression ie = null; 
		Primary(out e);
		s = e; ArrayRangeType ar1 = ArrayRangeType.Default, ar2 = ArrayRangeType.Default; 
		while (StartOf(11)) {
			switch (la.kind) {
			case 28: {
				Get();
				if (la.kind == 51) {
					Get();
					ar1 = ArrayRangeType.FromEnd; 
				}
				Expr(out e1);
				if (la.kind == 34) {
					Get();
					if (la.kind == 51) {
						Get();
						ar2 = ArrayRangeType.FromEnd; 
					}
					Expr(out e2);
				}
				Expect(29);
				s = new IndexedIdentifierExpression(e, ar1, e1, ar2, e2); 
				break;
			}
			case 35: {
				Get();
				Expect(1);
				ie = new InvocationExpression(s == null?e:s, t.val, InvocationType.CALL_OTHER); 
				Expect(26);
				if (StartOf(10)) {
					ArgExprList(ie);
				}
				Expect(27);
				s = ie; 
				break;
			}
			case 36: {
				Get();
				Expect(1);
				ie = new InvocationExpression(s == null?e:s, t.val, InvocationType.CALL_INHERITED); 
				Expect(26);
				if (StartOf(10)) {
					ArgExprList(ie);
				}
				Expect(27);
				s = ie; 
				break;
			}
			case 26: {
				Get();
				ie = new InvocationExpression(s == null?e:s); 
				if (StartOf(10)) {
					ArgExprList(ie);
				}
				Expect(27);
				s = ie; 
				break;
			}
			case 92: {
				Get();
				op = UnaryOperatorType.PostIncrement; s = new UnaryExpression(op, e); 
				break;
			}
			case 93: {
				Get();
				op = UnaryOperatorType.PostDecrement; s = new UnaryExpression(op, e); 
				break;
			}
			}
		}
	}

	void UnaryOp(out UnaryOperatorType op) {
		op = UnaryOperatorType.Any; 
		if (la.kind == 47) {
			Get();
			op = UnaryOperatorType.AddressOf; 
		} else if (la.kind == 57) {
			Get();
			op = UnaryOperatorType.Plus; 
		} else if (la.kind == 58) {
			Get();
			op = UnaryOperatorType.Minus; 
		} else if (la.kind == 87) {
			Get();
			op = UnaryOperatorType.BitNot; 
		} else if (la.kind == 88) {
			Get();
			op = UnaryOperatorType.Not; 
		} else SynErr(102);
	}

	void Primary(out Expression s) {
		s = null; Expression e; Expression ce = null; 
		if (la.kind == 1) {
			Get();
			s = new IdentifierExpression(t.val); 
		} else if (StartOf(12)) {
			Literal(out ce);
			s = ce; 
		} else if (la.kind == 26) {
			Get();
			Expr(out e);
			Expect(27);
			s = new ParenthesizedExpression(e); 
		} else SynErr(103);
	}

	void ArgExprList(InvocationExpression ie) {
		Expression e; 
		AssignExpr(out e);
		ie.AddArgument(e); 
		while (la.kind == 24) {
			Get();
			AssignExpr(out e);
			ie.AddArgument(e); 
		}
	}

	void Literal(out Expression ce) {
		ce = null; 
		switch (la.kind) {
		case 3: {
			Get();
			ce = new ConstantExpression(t.val, AType.TYPE_LONG); 
			break;
		}
		case 2: {
			Get();
			ce = new ConstantExpression(t.val, AType.TYPE_REAL);   
			break;
		}
		case 5: {
			Get();
			ce = new ConstantExpression(t.val, AType.TYPE_STRING); 
			break;
		}
		case 4: {
			Get();
			ce = new ConstantExpression(t.val, AType.TYPE_STRING); 
			break;
		}
		case 89: {
			Get();
			ce = new ConstantExpression(t.val, AType.TYPE_BOOL);   
			break;
		}
		case 90: {
			Get();
			ce = new ConstantExpression(t.val, AType.TYPE_BOOL);   
			break;
		}
		case 91: {
			Get();
			ce = new NullReferenceExpression(); 
			break;
		}
		default: SynErr(104); break;
		}
	}

	void Stat(out Statement s) {
		Expression e = null, e1 = null, e2 = null; s = null; Statement s1 = null, s2 = null; BlockStatement block = null; int beginPos = la.charPos; 
		switch (la.kind) {
		case 1: case 2: case 3: case 4: case 5: case 9: case 26: case 47: case 57: case 58: case 62: case 64: case 65: case 87: case 88: case 89: case 90: case 91: case 92: case 93: {
			Expr(out e);
			Expect(25);
			s = new ExpressionStatement(e); s.Annotation = scanner.buffer.GetString(beginPos, la.charPos); 
			break;
		}
		case 30: {
			Block(out block);
			s = block; 
			break;
		}
		case 69: {
			Get();
			Expect(26);
			Expr(out e);
			Expect(27);
			Stat(out s1);
			if (la.kind == 70) {
				Get();
				Stat(out s2);
			}
			s = new ExpressionStatement(new IfElseExpression(e, s1, s2)); s.Annotation = scanner.buffer.GetString(beginPos, la.charPos); 
			break;
		}
		case 71: {
			Get();
			Expect(26);
			Expr(out e);
			Expect(27);
			s = new SwitchStatement(e); s.Annotation = scanner.buffer.GetString(beginPos, la.charPos); SwitchSectionNode ss = null; 
			Expect(30);
			while (la.kind == 8 || la.kind == 11) {
				SwitchSection(out ss);
				s.AddNode(ss); 
			}
			Expect(31);
			break;
		}
		case 72: {
			Get();
			Expect(26);
			Expr(out e);
			Expect(27);
			Stat(out s1);
			s = new WhileStatement(e, s1); 
			break;
		}
		case 73: {
			Get();
			Stat(out s1);
			Expect(72);
			Expect(26);
			Expr(out e);
			Expect(27);
			Expect(25);
			s = new DoWhileStatement(s1, e); 
			break;
		}
		case 74: {
			Get();
			Expect(26);
			s = null; ForStatement f = new ForStatement(); AstNodeCollection nodes = f.Initializers; 
			if (StartOf(3)) {
				LocalVarDecl(nodes);
			} else if (StartOf(13)) {
				if (StartOf(10)) {
					Expr(out e);
				}
				f.Initializers.Add(new ExpressionStatement(e)); 
			} else SynErr(105);
			Expect(25);
			if (StartOf(10)) {
				Expr(out e1);
			}
			Expect(25);
			f.Expression = e1; 
			if (StartOf(10)) {
				Expr(out e2);
			}
			f.Inc = e2; 
			Expect(27);
			Stat(out s1);
			f.Statement = s1; s = f; 
			break;
		}
		case 75: {
			Get();
			Expect(26);
			AType type; string varName = string.Empty; 
			TypeSpecifier(out type);
			Expect(1);
			varName = t.val; _func.LocalDataSize++; Symbols.Add(varName); 
			Expect(76);
			Expr(out e);
			_func.LocalDataSize += 2; 
			Expect(27);
			Stat(out s1);
			s = new ForEachStatement(type, varName, e, s1); 
			break;
		}
		case 66: {
			Get();
			Expect(25);
			s = new ContinueStatement(); 
			break;
		}
		case 67: {
			Get();
			Expect(25);
			s = new BreakStatement(); 
			break;
		}
		case 68: {
			Get();
			if (StartOf(10)) {
				Expr(out e);
			}
			Expect(25);
			s = new ReturnStatement(e); 
			break;
		}
		default: SynErr(106); break;
		}
	}

	void SwitchSection(out SwitchSectionNode section) {
		section = new SwitchSectionNode(); CaseLabel l = null; Statement s = null; 
		SwitchLabel(out l);
		section.AddLabel(l); 
		while (la.kind == 8 || la.kind == 11) {
			SwitchLabel(out l);
			section.AddLabel(l); 
		}
		Stat(out s);
		section.AddNode(s); 
		while (StartOf(14)) {
			Stat(out s);
			section.AddNode(s); 
		}
	}

	void LocalVarDecl(AstNodeCollection nodes) {
		VariableDeclarationStatement vds = null; AType type; 
		TypeSpecifier(out type);
		LocalVar(out vds);
		vds.Type = type; nodes.Add(vds); _func.LocalDataSize++; Symbols.Add(vds.Name); 
		while (la.kind == 24) {
			Get();
			LocalVar(out vds);
			vds.Type = type; nodes.Add(vds); _func.LocalDataSize++; Symbols.Add(vds.Name); 
		}
	}

	void LocalVar(out VariableDeclarationStatement vds) {
		Expression e = null; 
		Expect(1);
		vds = new VariableDeclarationStatement(t.val); 
		if (la.kind == 32) {
			Get();
			Expr(out e);
			vds.Initializer = e; 
		}
	}

	void SwitchLabel(out CaseLabel l) {
		Expression e = null; l = null; 
		if (la.kind == 8) {
			Get();
			Expr(out e);
			Expect(37);
			l = new CaseLabel(e); 
		} else if (la.kind == 11) {
			Get();
			Expect(37);
			l = new CaseLabel(); 
		} else SynErr(107);
	}



	public CompilationUnit Parse() {
		la = new Token();
		la.val = "";		
		Get();
		C();
		Expect(0);

		return CompilationUnit;
	}
	
	static readonly bool[,] set = {
		{T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x},
		{x,T,x,x, x,x,T,T, x,x,T,x, T,T,x,T, T,T,T,T, T,T,x,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,T,T,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x},
		{x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,T,T,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x},
		{x,T,x,x, x,x,T,T, x,x,T,x, T,x,x,T, T,T,T,T, T,T,x,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x},
		{x,T,T,T, T,T,T,T, x,T,T,x, T,x,x,T, T,T,T,T, T,T,x,T, x,x,T,x, x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, x,x,x,x, x,x,x,x, x,T,T,x, x,x,T,x, T,T,T,T, T,T,x,T, T,T,T,T, x,x,x,x, x,x,x,x, x,x,x,T, T,T,T,T, T,T,x,x},
		{x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,T,T, T,T,T,T, T,T,T,x, x,x,x,x, x,x,x,x},
		{x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, T,T,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x},
		{x,T,T,T, T,T,x,x, x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, x,x,x,x, x,x,x,x, x,T,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, T,T,T,T, T,T,x,x},
		{x,T,T,T, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,T,T, x,x,x,x},
		{x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, x,x,x,x, x,x,x,x, x,T,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, T,x,x,x, x,x,x,x},
		{x,T,T,T, T,T,x,x, x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, x,x,x,x, x,x,x,x, x,T,T,x, x,x,T,x, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, T,T,T,T, T,T,x,x},
		{x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,x, T,x,x,x, x,x,x,T, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,T,x,x},
		{x,x,T,T, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,T,T, x,x,x,x},
		{x,T,T,T, T,T,x,x, x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, x,x,x,x, x,x,x,x, x,T,T,x, x,x,T,x, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, T,T,T,T, T,T,x,x},
		{x,T,T,T, T,T,x,x, x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,x, x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, x,x,x,x, x,x,x,x, x,T,T,x, x,x,T,x, T,T,T,T, T,T,x,T, T,T,T,T, x,x,x,x, x,x,x,x, x,x,x,T, T,T,T,T, T,T,x,x}

	};
} // end Parser


public class Errors {
	public int count = 0;                                    // number of errors detected
	public System.IO.TextWriter errorStream = Console.Out;   // error messages go to this stream
	public string errMsgFormat = "-- line {0} col {1}: {2}"; // 0=line, 1=column, 2=text

	public virtual void SynErr (int line, int col, int n) {
		string s;
		switch (n) {
			case 0: s = "EOF expected"; break;
			case 1: s = "ident expected"; break;
			case 2: s = "floatcon expected"; break;
			case 3: s = "intcon expected"; break;
			case 4: s = "stringcon expected"; break;
			case 5: s = "charcon expected"; break;
			case 6: s = "array expected"; break;
			case 7: s = "bool expected"; break;
			case 8: s = "case expected"; break;
			case 9: s = "catch expected"; break;
			case 10: s = "char expected"; break;
			case 11: s = "default expected"; break;
			case 12: s = "double expected"; break;
			case 13: s = "enum expected"; break;
			case 14: s = "float expected"; break;
			case 15: s = "int expected"; break;
			case 16: s = "long expected"; break;
			case 17: s = "var expected"; break;
			case 18: s = "map expected"; break;
			case 19: s = "object expected"; break;
			case 20: s = "short expected"; break;
			case 21: s = "string expected"; break;
			case 22: s = "struct expected"; break;
			case 23: s = "void expected"; break;
			case 24: s = "comma expected"; break;
			case 25: s = "semicolon expected"; break;
			case 26: s = "lpar expected"; break;
			case 27: s = "rpar expected"; break;
			case 28: s = "lbrack expected"; break;
			case 29: s = "rbrack expected"; break;
			case 30: s = "lbrace expected"; break;
			case 31: s = "rbrace expected"; break;
			case 32: s = "assgn expected"; break;
			case 33: s = "ellipsis expected"; break;
			case 34: s = "range expected"; break;
			case 35: s = "arrow expected"; break;
			case 36: s = "dcolon expected"; break;
			case 37: s = "colon expected"; break;
			case 38: s = "qmark expected"; break;
			case 39: s = "inherit expected"; break;
			case 40: s = "public expected"; break;
			case 41: s = "private expected"; break;
			case 42: s = "readonly expected"; break;
			case 43: s = "static expected"; break;
			case 44: s = "qor expected"; break;
			case 45: s = "qand expected"; break;
			case 46: s = "bor expected"; break;
			case 47: s = "band expected"; break;
			case 48: s = "bxor expected"; break;
			case 49: s = "eq expected"; break;
			case 50: s = "neq expected"; break;
			case 51: s = "lt expected"; break;
			case 52: s = "gt expected"; break;
			case 53: s = "lte expected"; break;
			case 54: s = "gte expected"; break;
			case 55: s = "lsh expected"; break;
			case 56: s = "rsh expected"; break;
			case 57: s = "add expected"; break;
			case 58: s = "sub expected"; break;
			case 59: s = "mul expected"; break;
			case 60: s = "div expected"; break;
			case 61: s = "mod expected"; break;
			case 62: s = "lams expected"; break;
			case 63: s = "lame expected"; break;
			case 64: s = "maps expected"; break;
			case 65: s = "arrays expected"; break;
			case 66: s = "continue expected"; break;
			case 67: s = "break expected"; break;
			case 68: s = "return expected"; break;
			case 69: s = "if expected"; break;
			case 70: s = "else expected"; break;
			case 71: s = "switch expected"; break;
			case 72: s = "while expected"; break;
			case 73: s = "do expected"; break;
			case 74: s = "for expected"; break;
			case 75: s = "foreach expected"; break;
			case 76: s = "in expected"; break;
			case 77: s = "assignmul expected"; break;
			case 78: s = "assigndiv expected"; break;
			case 79: s = "assignmod expected"; break;
			case 80: s = "assignadd expected"; break;
			case 81: s = "assignsub expected"; break;
			case 82: s = "assignshl expected"; break;
			case 83: s = "assignshr expected"; break;
			case 84: s = "assignand expected"; break;
			case 85: s = "assignxor expected"; break;
			case 86: s = "assignor expected"; break;
			case 87: s = "bnot expected"; break;
			case 88: s = "not expected"; break;
			case 89: s = "true expected"; break;
			case 90: s = "false expected"; break;
			case 91: s = "null expected"; break;
			case 92: s = "incr expected"; break;
			case 93: s = "decr expected"; break;
			case 94: s = "??? expected"; break;
			case 95: s = "invalid MemberModifier"; break;
			case 96: s = "invalid MemberDeclarator"; break;
			case 97: s = "invalid MemberDeclarator"; break;
			case 98: s = "invalid TypeSpecifier"; break;
			case 99: s = "invalid AssignOp"; break;
			case 100: s = "invalid CastExpr"; break;
			case 101: s = "invalid UnaryExpr"; break;
			case 102: s = "invalid UnaryOp"; break;
			case 103: s = "invalid Primary"; break;
			case 104: s = "invalid Literal"; break;
			case 105: s = "invalid Stat"; break;
			case 106: s = "invalid Stat"; break;
			case 107: s = "invalid SwitchLabel"; break;

			default: s = "error " + n; break;
		}
		errorStream.WriteLine(errMsgFormat, line, col, s);
		count++;
	}

	public virtual void SemErr (int line, int col, string s) {
		errorStream.WriteLine(errMsgFormat, line, col, s);
		count++;
	}
	
	public virtual void SemErr (string s) {
		errorStream.WriteLine(s);
		count++;
	}
	
	public virtual void Warning (int line, int col, string s) {
		errorStream.WriteLine(errMsgFormat, line, col, s);
	}
	
	public virtual void Warning(string s) {
		errorStream.WriteLine(s);
	}
} // Errors


public class FatalError: Exception {
	public FatalError(string m): base(m) {}
}
}